home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Almathera Ten Pack 2: CDPD 1
/
Almathera Ten on Ten - Disc 2: CDPD 1.iso
/
pd
/
076-100
/
092
/
bawk
/
bawk.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-03-13
|
13KB
|
678 lines
/*
* Bawk main program
*/
#define MAIN 1
#include <stdio.h>
#include "bawk.h"
static char *pattern_arg = NULL; /* Command line bawk program pattern */
static int ungetc_arg = 0;
static char eof_seen = 0;
static int max_field_count = 0;
/*
* Main program
*/
main( argc, argv )
register int argc;
register char **argv;
{
register char gotrules = 0, didfile = 0, getstdin = 0;
register char rule_file_flag = 0;
DBUG_ENTER("main");
/*
* Initialize global variables:
*/
Beginact = 0;
Endact = 0;
Rules = 0;
Rulep = 0;
Filename = 0;
Linecount = 0;
Saw_break = 0;
Stackptr = Stackbtm - 1;
Stacktop = Stackbtm + MAXSTACKSZ;
Nextvar = Vartab;
init_pop_array();
strcpy( Fieldsep, " \t" );
strcpy( Recordsep, "\n" );
/*
* Parse command line
*/
while ( --argc )
{
if ( **(++argv) == '-' )
{
/*
* Process dash options.
*/
switch ( tolower( argv[0][1] ) )
{
case '#':
DBUG_PUSH(&argv[0][2]);
continue;
case 'f':
if(!gotrules) {
rule_file_flag++;
argv++;
argc--;
} else
usage();
break;
case 0:
if(!gotrules)
rule_file_flag++;
getstdin++;
break;
default: usage();
}
}
if ( gotrules )
{
/*
* Already read rules file - assume this is
* is a text file for processing.
*/
if ( ++didfile == 1 && Beginact )
doaction( Beginact );
if ( getstdin )
{
getstdin--;
newfile( 0 );
}
else
newfile( *argv );
process();
}
else
{
if(rule_file_flag) {
if ( getstdin )
{
getstdin--;
newfile( 0 );
}
else
newfile( *argv );
} else
pattern_arg = *argv;
compile();
pattern_arg = NULL;
gotrules = 1;
}
}
if ( !gotrules )
usage();
if ( ! didfile )
{
/*
* Didn't process any files yet - process stdin.
*/
newfile( 0 );
if ( Beginact )
doaction( Beginact );
process();
}
if ( Endact )
doaction( Endact );
DBUG_RETURN(0);
}
/*
* Regular expression/action file compilation routines.
*/
void compile()
{
/*
* Compile regular expressions and C actions into Rules struct,
* reading from current input file "Fileptr".
*/
register int c;
register EXPR_NODE *root;
DBUG_ENTER("compile");
while ( (c = getcharacter()) != -1 )
{
if ( c==' ' || c=='\t' || c=='\n' )
/* swallow whitespace */
;
else if ( c=='#' )
{
/*
* Swallow comments
*/
while ( (c=getcharacter()) != -1 && c!='\n' )
;
}
else if ( c=='{' )
{
DBUG_PRINT("compile",("action"));
/*
* Compile the action string into a parse tree
*/
ungetcharacter( (char) '{' );
if ( Rulep && Rulep->action )
{
Rulep->nextrule = (RULE *)
get_clear_memory( sizeof( *Rulep ) );
Rulep = Rulep->nextrule;
}
if ( !Rulep )
{
/*
* This is the first action encountered.
* Allocate the first Rules structure and
* initialize it
*/
Rules = Rulep = (RULE *)
get_clear_memory( sizeof( *Rulep ) );
}
Rulep->action = act_compile( Workbuf );
}
else if ( c==',' )
{
DBUG_PRINT("compile",("stop pattern"));
/*
* It's (hopefully) the second part of a two-part
* pattern string. Swallow the comma and start
* compiling an action string.
*/
if ( !Rulep || !Rulep->pattern.start )
error( "stop pattern without a start",
RE_ERROR );
if ( Rulep->pattern.stop )
error( "already have a stop pattern",
RE_ERROR );
Rulep->pattern.stop = pat_compile( Workbuf );
}
else
{
/*
* Assume it's a regular expression pattern
*/
DBUG_PRINT("compile",("start pattern"));
ungetcharacter( (char) c );
root = pat_compile( Workbuf );
if ( *Workbuf == T_BEGIN )
{
/*
* Saw a "BEGIN" keyword - compile following
* action into special "Beginact" parse tree.
*/
Beginact = act_compile( Workbuf );
continue;
}
if ( *Workbuf == T_END )
{
/*
* Saw an "END" keyword - compile following
* action into special "Endact" parse tree.
*/
Endact = act_compile( Workbuf );
continue;
}
if ( Rulep )
{
/*
* Already saw a pattern/action - link in
* another Rules structure.
*/
Rulep->nextrule = (RULE *)
get_clear_memory( sizeof( *Rulep ) );
Rulep = Rulep->nextrule;
}
if ( !Rulep )
{
/*
* This is the first pattern encountered.
* Allocate the first Rules structure and
* initialize it
*/
Rules = Rulep = (RULE *)
get_clear_memory( sizeof( *Rulep ) );
}
if ( Rulep->pattern.start )
error( "already have a start pattern",
RE_ERROR );
Rulep->pattern.start = root;
}
}
for(Rulep = Rules; Rulep; Rulep = Rulep->nextrule)
{
if(!Rulep->action) {
pattern_arg = "{printf \"%s\n\", $0}";
Rulep->action = act_compile( Workbuf );
pattern_arg = NULL;
}
}
endfile();
DBUG_VOID_RETURN;
}
/*
* Text file main processing loop.
*/
void process()
{
/*
* Read a line at a time from current input file at "Fileptr",
* then apply each rule in the Rules chain to the input line.
*/
register int i;
DBUG_ENTER("process");
Recordcount = 0;
while ( getline() )
{
/*
* Parse the input line.
*/
if(! *Recordsep )
strcpy(Fieldsep," \t\n");
Fieldcount = parse( Linebuf, Fields, Fieldsep );
DBUG_PRINT("process",( "parsed %d words:", Fieldcount ));
DBUG_EXECUTE("process",for(i=0; i<Fieldcount; ++i )DBUG_PRINT("process",("<%s>",Fields[i])););
Rulep = Rules;
while(Rulep)
{
if ( ! Rulep->pattern.start )
{
/*
* No pattern given - perform action on
* every input line.
*/
doaction( Rulep->action );
}
else if ( Rulep->pattern.startseen )
{
/*
* Start pattern already found - perform
* action then check if line matches
* stop pattern.
*/
doaction( Rulep->action );
if ( dopattern( Rulep->pattern.stop ) )
Rulep->pattern.startseen = 0;
}
else if ( dopattern( Rulep->pattern.start ) )
{
/*
* Matched start pattern - perform action.
* If a stop pattern was given, set "start
* pattern seen" flag and process every input
* line until stop pattern found.
*/
doaction( Rulep->action );
if ( Rulep->pattern.stop )
Rulep->pattern.startseen = 1;
}
Rulep = Rulep->nextrule;
}
}
DBUG_VOID_RETURN;
}
/*
* Miscellaneous functions
*/
parse( str, wrdlst, delim )
register char *str;
char *wrdlst[];
char *delim;
{
/*
* Parse the string of words in "str" into the word list at "wrdlst".
* A "word" is a sequence of characters delimited by one or more
* of the characters found in the string "delim".
* Returns the number of words parsed.
*/
register int wrdcnt;
register char *cp, *wrdcp, c;
char wrdbuf[ MAXLINELEN+1 ];
DBUG_ENTER("parse");
wrdcnt = 0;
while ( *str )
{
while(c = *str++)
{
cp = delim;
while(*cp && c != *cp)
cp++;
if(! *cp)
break;
}
str--;
if ( !*str )
break;
wrdcp = wrdbuf;
while(c = *str++)
{
cp = delim;
while(*cp && c != *cp)
cp++;
if(*cp)
break;
*wrdcp++ = c;
}
str--;
*wrdcp = 0;
/*
* NOTE: allocate a MAXLINELEN sized buffer for every
* word, just in case user wants to copy a larger string
* into a field.
*/
if(wrdcnt == max_field_count)
{
wrdlst[ wrdcnt ] = getmemory( MAXLINELEN+1 );
max_field_count++;
}
strcpy( wrdlst[ wrdcnt++ ], wrdbuf );
}
DBUG_RETURN(wrdcnt);
}
void unparse( wrdlst, wrdcnt, str, delim )
char *wrdlst[];
register int wrdcnt;
register char *str;
char *delim;
{
/*
* Replace all the words in "str" with the words in "wrdlst",
* maintaining the same word seperation distance as found in
* the string.
* A "word" is a sequence of characters delimited by one or more
* of the characters found in the string "delim".
*/
register int wc;
register char *sp, *cp, c;
char strbuf[ MAXLINELEN+1 ], *start;
DBUG_ENTER("unparse");
wc = 0; /* next word in "wrdlst" */
sp = strbuf; /* points to our local string */
start = str; /* save start address of "str" for later... */
while ( *str )
{
/*
* Copy the field delimiters from the original string to
* our local version.
*/
while(c = *str++)
{
cp = delim;
while(*cp && c != *cp)
cp++;
if(!*cp)
break;
*sp++ = c;
}
str--;
if ( !*str )
break;
/*
* Skip over the field in the original string and...
*/
while(c = *str++)
{
cp = delim;
while(*cp && c != *cp)
cp++;
if(*cp)
break;
}
str--;
if ( wc < wrdcnt )
{
/*
* ...copy in the field in the wordlist instead.
*/
cp = wrdlst[ wc++ ];
while(*sp++ = *cp++);
sp--;
}
}
/*
* Tie off the local string, then copy it back to caller's string.
*/
*sp = 0;
strcpy( start, strbuf );
DBUG_VOID_RETURN;
}
char *
getmemory( len )
register unsigned len;
{
register char *cp;
DBUG_ENTER("getmemory");
if ( cp=malloc( len ) )
DBUG_RETURN(cp);
error( "out of memory", MEM_ERROR );
DBUG_RETURN(NULL);
}
char *
get_clear_memory( len )
register unsigned len;
{
register char *cp;
DBUG_ENTER("getmemory");
if ( cp=calloc( 1, len ) )
DBUG_RETURN(cp);
error( "out of memory", MEM_ERROR );
DBUG_RETURN(NULL);
}
EXPR_NODE *get_expr_node(operator)
char operator;
{
register EXPR_NODE *node;
DBUG_ENTER("get_expr_node");
node = (EXPR_NODE *) getmemory(sizeof(EXPR_NODE));
node->left = node->right = NULL;
node->operator = operator;
DBUG_PRINT("get_expr_node",("operator = '%s'",token_name[operator]));
DBUG_RETURN(node);
}
void newfile( s )
register char *s;
{
DBUG_ENTER("newfile");
Linecount = 0;
if ( Filename = s )
{
#ifdef BDS_C
if ( fopen( s, Fileptr = Curfbuf ) == -1 )
#else
if ( !(Fileptr = fopen( s, "r" )) )
#endif
error( "file not found", FILE_ERROR );
}
else
{
/*
* No file name given - process standard input.
*/
Fileptr = stdin;
Filename = "standard input";
}
DBUG_VOID_RETURN;
}
getline()
{
/*
* Read a record from current input file.
*/
register int rtn, len = 0;
register char *cp = Linebuf, *last_nl, *sep = Recordsep;
DBUG_ENTER("getline");
if(eof_seen)
{
endfile();
DBUG_RETURN(0);
}
if(*sep)
{
while((*cp++ = rtn = getcharacter()) != *sep++ && rtn != -1)
{
while(*sep)
{
if(rtn == *sep++)
break;
}
if( ++len == MAXLINELEN )
error("Input record too long", RECORD_ERROR);
sep = Recordsep;
}
} else /* Treat an empty line as record separator. */
{
while(1)
{
last_nl = cp;
while((*cp++ = rtn = getcharacter()) != '\n' &&
rtn != -1)
{
if( ++len == MAXLINELEN )
error("Input record too long",
RECORD_ERROR);
}
if(((cp - last_nl) == 1) || (rtn == -1))
break;
}
}
*(--cp) = 0;
if ( rtn == -1 )
{
if(len)
eof_seen = 1;
else
{
endfile();
DBUG_RETURN(0);
}
}
++Recordcount;
DBUG_RETURN(1);
}
int getcharacter()
{
/*
* Read a character from curren input file.
* WARNING: your getc() must convert lines that end with CR+LF
* to LF and CP/M's EOF character (^Z) to a -1.
* Also, getc() must return a -1 when attempting to read from
* an unopened file.
*/
register int c;
DBUG_ENTER("getcharacter");
if(pattern_arg) {
if(ungetc_arg) {
c = ungetc_arg;
ungetc_arg = 0;
} else if(*pattern_arg)
c = *pattern_arg++;
else
c = EOF;
} else {
#ifdef BDS_C
/*
* BDS C doesn't do CR+LF to LF and ^Z to -1 conversions
* <gag>
*/
if ( (c = getc( Fileptr )) == '\r' )
{
if ( (c = getc( Fileptr )) != '\n' )
{
ungetc( c );
c = '\r';
}
}
else if ( c == 26 ) /* ^Z */
c = -1;
#else
c = getc( Fileptr );
#endif
if ( c=='\n' )
++Linecount;
}
DBUG_PRINT("getcharacter",("'%c'", c));
DBUG_RETURN(c);
}
ungetcharacter( c )
register char c;
{
/*
* Push a character back into the input stream.
* If the character is a record seperator, or a newline character,
* the record and line counters are adjusted appropriately.
*/
DBUG_ENTER("ungetcharacter");
if ( c == *Recordsep )
--Recordcount;
if ( c=='\n' )
--Linecount;
DBUG_PRINT("ungetcharacter",("'%c'", c));
if(pattern_arg)
DBUG_RETURN(ungetc_arg = c);
DBUG_RETURN(ungetc( c, Fileptr ));
}
void endfile()
{
DBUG_ENTER("endfile");
fclose( Fileptr );
eof_seen = 0;
Filename = NULL;
Linecount = 0;
DBUG_VOID_RETURN;
}
void error( s, severe )
register char *s;
register int severe;
{
DBUG_ENTER("error");
if ( Filename )
fprintf( stderr, "%s:", Filename );
if ( Linecount )
fprintf( stderr, " line %d:", Linecount );
fprintf( stderr, " %s\n", s );
if ( severe )
exit( severe );
DBUG_VOID_RETURN;
}
void usage()
{
DBUG_ENTER("usage");
error( "Usage: bawk { action | - | -f <actfile> } <file> ...",
USAGE_ERROR );
DBUG_VOID_RETURN;
}